',
'foo-- ',
'foo--! ',
'[if IE] ',
'foo- ',
'foo- ',
' >
',
'---------- >
',
'--\uFFFD>']);
});
it('filter yav-single-quoted state transition test', function() {
testutils.test_yav(filter.yavs, [
'foo&
<>
'"` \t\n\x0B\f\r', '\f', '',
'''', ' ''', '\t ''', '\n ''', '\f ''',
'""', ' ""', '\t""', '\n""', '\f""',
'``', ' ``', '\t``', '\n``', '\f``']);
});
it('filter yav-double-quoted state transition test', function() {
testutils.test_yav(filter.yavd, [
'foo&
<>
\'"` \t\n\x0B\f\r', '\f', '',
"''", " ''", "\t''", "\n''", "\f''",
'""', ' ""', '\t ""', '\n ""', '\f ""',
'``', ' ``', '\t``', '\n``', '\f``']);
});
it('filter yav-unquoted state transition test', function() {
testutils.test_yav(filter.yavu, [
'foo&<>'"`
', '', '\uFFFD',
"''", " ''", " ''", "
''", "''",
'""', ' ""', ' ""', '
""', '""',
'``', ' ``', ' ``', '
``', '``']);
var s = "\x00=<>''onerror=alert(1)";
var o = filter.yavu(s);
expect(o).to.eql("\uFFFD =<>''onerror =alert(1)");
});
it('filter yu state transition test', function() {
testutils.test_yu(filter.yu);
});
it('filter yuc state transition test', function() {
testutils.test_yuc(filter.yuc);
});
it('filter yubl state transition test', function() {
testutils.test_yubl(filter.yubl, [
'x-\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\
\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\
\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\
\u001C\u001D\u001E\u001F\u0020j\nav a\rscript\t &col \u0000on;'
]);
});
it('filter yufull state transition test', function() {
testutils.test_yufull(filter.yufull, [
null, // default
null, // default
null, // default
null, // default
null, // default
'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]',
null, // default
null // default
]);
});
it('filter yublf state transition test', function() {
testutils.test_yufull(filter.yublf, [
null, // default
null, // default
null, // default
null, // default
null, // default
'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]',
null, // default
null // default
]);
testutils.test_yubl(filter.yublf, [
'%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20j%0Aav a%0Dscript%09 &col %00on;'
]);
});
});
describe("private-xss-filters: css expression tests", function() {
var testPatterns = [ undefined, null,
'&',
'1.1', '10%', '+10px', '-10px', '#fff',
'\uD7FF', '\uD800', '\uDFFF', '\u1234567',
'\u0000', ' ', '\r\n\t\f\x0B', '\\', '\\n\\r\\f\\0\\9\\a\\f',
'-ide_nt', '"string"', "'string'",
'- \ _ : ; ( ) " \' / , % # ! * @ . { } []',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'url(https://www.evil.com)',
'u\x00\x00rl(https://www.evil.com)',
'\\u\\r\x00\x00\\l\x00\\((evil.com))',
'expression(body.scrollTop + 50 + px)',
'(((()))) \\28 \\29'
];
it('filter yceu[uds] test', function() {
var expectedResults = [ 'undefined', 'null',
';-x:\'&\';-v:',
'1.1', '10%', '+10px', '-10px', '#fff',
';-x:\'\uD7FF\';-v:', ';-x:\'\uD800\';-v:', ';-x:\'\uDFFF\';-v:', ';-x:\'\u1234567\';-v:',
';-x:\'\uFFFD\';-v:', ';-x:\' \';-v:', ';-x:\'\\d \\a \\9 \\c \\b \';-v:', ';-x:\'\\5c \';-v:', ';-x:\'\\5c n\\5c r\\5c f\\5c 0\\5c 9\\5c a\\5c f\';-v:',
'-ide_nt', ';-x:\'"string"\';-v:', ';-x:\'\\27 string\\27 \';-v:',
';-x:\'- _ : ; ( ) " \\27 / , % # ! * @ . \\7b \\7d \\5b \\5d \';-v:',
';-x:\'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash\';-v:',
';-x:\'-x-url(https://www.evil.com)\';-v:',
';-x:\'u\ufffd\ufffdrl(https://www.evil.com)\';-v:',
';-x:\'\\5c u\\5c r\ufffd\ufffd\\5c l\ufffd\\5c ((evil.com))\';-v:',
';-x:\'expression(body.scrollTop + 50 + px)\';-v:',
';-x:\'(((()))) \\5c 28 \\5c 29\';-v:'
];
testutils.test_yce(filter.yceu, testPatterns, expectedResults);
});
it('filter yced[uds] test', function() {
var expectedResults = [ 'undefined', 'null',
'&',
'1.1', '10%', '+10px', '-10px', '#fff',
'\uD7FF', '\uD800', '\uDFFF', '\u1234567',
'\uFFFD', ' ', '\\d \\a \\9 \\c \\b ', '\\5c ', '\\5c n\\5c r\\5c f\\5c 0\\5c 9\\5c a\\5c f',
'-ide_nt', '\\22 string\\22 ', "'string'",
'- _ : ; ( ) \\22 \' / , % # ! * @ . \\7b \\7d \\5b \\5d ',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'-x-url(https://www.evil.com)',
'u\ufffd\ufffdrl(https://www.evil.com)',
'\\5c u\\5c r\ufffd\ufffd\\5c l\ufffd\\5c ((evil.com))',
'expression(body.scrollTop + 50 + px)',
'(((()))) \\5c 28 \\5c 29'
];
testutils.test_yce(filter.yced, testPatterns, expectedResults);
});
it('filter yces[uds] test', function() {
var expectedResults = [ 'undefined', 'null',
'&',
'1.1', '10%', '+10px', '-10px', '#fff',
'\uD7FF', '\uD800', '\uDFFF', '\u1234567',
'\uFFFD', ' ', '\\d \\a \\9 \\c \\b ', '\\5c ', '\\5c n\\5c r\\5c f\\5c 0\\5c 9\\5c a\\5c f',
'-ide_nt', '"string"', "\\27 string\\27 ",
'- _ : ; ( ) " \\27 / , % # ! * @ . \\7b \\7d \\5b \\5d ',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'-x-url(https://www.evil.com)',
'u\ufffd\ufffdrl(https://www.evil.com)',
'\\5c u\\5c r\ufffd\ufffd\\5c l\ufffd\\5c ((evil.com))',
'expression(body.scrollTop + 50 + px)',
'(((()))) \\5c 28 \\5c 29'
];
testutils.test_yce(filter.yces, testPatterns, expectedResults);
});
});
describe("private-xss-filters: css url tests", function() {
var testPatterns = [ undefined, null,
'&',
'1.1', '10%', '+10px', '-10px', '#fff',
'\\a', '\uD7FF', '\u1234567',
'\u0000', ' ', '\r\n\t\f\x0B', '\\', '\\n\\r\\f\\0\\9\\a\\f',
'-ide_nt', '"string"', "'string'",
'- \ _ : ; ( ) " \' / , % # ! * @ . { } [ ]',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'\u0000\u0008\u000b\u007f\u000e-\u001f',
')))((('''"""" ',
'javascript:alert(1)',
'(((()))) \\28 \\29'
];
it('filter yceuu[uds] attribute test', function() {
var expectedResults = [ 'undefined', 'null',
'&',
'1.1', '10%25', '+10px', '-10px', '#fff',
'%5Ca', '%ED%9F%BF', '%E1%88%B4567',
'%EF%BF%BD', '%20', '%0D%0A%09%0C%0B', '%5C', '%5Cn%5Cr%5Cf%5C0%5C9%5Ca%5Cf',
'-ide_nt', '%22string%22', "\\27 string\\27 ",
'-%20%20_%20:%20;%20%28%20%29%20%22%20\\27 %20/%20,%20%25%20#%20!%20*%20@%20.%20%7B%20%7D%20%5B%20%5D',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'%EF%BF%BD%08%0B%7F%0E-%1F',
'%29%29%29%28%28%28\\27 \\27 \\27 %22%22%22%22',
'##javascript:alert%281%29',
'%28%28%28%28%29%29%29%29%20%5C28%20%5C29'
];
testutils.test_yce(filter.yceuu, testPatterns, expectedResults);
});
it('filter yceud[uds] test', function() {
var expectedResults = [ 'undefined', 'null',
'&',
'1.1', '10%25', '+10px', '-10px', '#fff',
'%5Ca', '%ED%9F%BF', '%E1%88%B4567',
'%EF%BF%BD', '%20', '%0D%0A%09%0C%0B', '%5C', '%5Cn%5Cr%5Cf%5C0%5C9%5Ca%5Cf',
'-ide_nt', '%22string%22', "'string'",
'-%20%20_%20:%20;%20(%20)%20%22%20\'%20/%20,%20%25%20#%20!%20*%20@%20.%20%7B%20%7D%20%5B%20%5D',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'%EF%BF%BD%08%0B%7F%0E-%1F',
')))(((\'\'\'%22%22%22%22',
'##javascript:alert(1)',
'(((())))%20%5C28%20%5C29'
];
testutils.test_yce(filter.yceud, testPatterns, expectedResults);
});
it('filter yceus[uds] test', function() {
var expectedResults = [ 'undefined', 'null',
'&',
'1.1', '10%25', '+10px', '-10px', '#fff',
'%5Ca', '%ED%9F%BF', '%E1%88%B4567',
'%EF%BF%BD', '%20', '%0D%0A%09%0C%0B', '%5C', '%5Cn%5Cr%5Cf%5C0%5C9%5Ca%5Cf',
'-ide_nt', '%22string%22', "\\27 string\\27 ",
'-%20%20_%20:%20;%20(%20)%20%22%20\\27 %20/%20,%20%25%20#%20!%20*%20@%20.%20%7B%20%7D%20%5B%20%5D',
'http://username:password@www.evil.com:8080/?k1=v1 &k2 =v2#hash',
'%EF%BF%BD%08%0B%7F%0E-%1F',
')))(((\\27 \\27 \\27 %22%22%22%22',
'##javascript:alert(1)',
'(((())))%20%5C28%20%5C29'
];
testutils.test_yce(filter.yceus, testPatterns, expectedResults);
});
});
describe("private-xss-filters: utility tests", function() {
it('htmlDecode d exists', function() {
expect(filter.d).to.be.ok();
});
it('htmlDecode d test', function() {
expect(filter.d(null)).to.equal('null');
expect(filter.d()).to.equal('undefined');
expect(filter.d('Á
')).to.equal('Á\uFFFD\uFFFD\u20AC\u201A\u201D\u0178\uFFFD\uFFFD');
});
it('frCoPt exists', function() {
expect(filter.frCoPt).to.be.ok();
});
it('frCoPt test', function() {
expect(filter.frCoPt(null)).to.equal('');
expect(filter.frCoPt()).to.equal('');
expect(filter.frCoPt(0)).to.equal('\uFFFD');
expect(filter.frCoPt(10)).to.equal('\n');
expect(filter.frCoPt(0x0B)).to.equal('\uFFFD');
expect(filter.frCoPt(0x10FFFF)).to.equal('\uFFFD');
});
});
}());
exports._getPrivFilters = function () {
var LT = /])/g,
SPECIAL_HTML_CHARS = /[&<>"'`]/g,
SPECIAL_COMMENT_CHARS = /(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g;
var SENSITIVE_HTML_ENTITIES = /&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,
SENSITIVE_NAMED_REF_MAP = {Tab: '\t', NewLine: '\n', colon: ':', semi: ';', lpar: '(', rpar: ')', apos: '\'', sol: '/', comma: ',', excl: '!', ast: '*', midast: '*', ensp: '\u2002', emsp: '\u2003', thinsp: '\u2009', nbsp: '\xA0', amp: '&', lt: '<', gt: '>', quot: '"', QUOT: '"'};
var CSS_VALID_VALUE = /^(?:(?!-*expression)#?[-\w]+|[+-]?(?:\d+|\d*\.\d+)(?:r?em|ex|ch|cm|mm|in|px|pt|pc|%|vh|vw|vmin|vmax)?|!important|)$/i,
CSS_DOUBLE_QUOTED_CHARS = /[\x00-\x1F\x7F\[\]{}\\"]/g,
CSS_SINGLE_QUOTED_CHARS = /[\x00-\x1F\x7F\[\]{}\\']/g,
CSS_BLACKLIST = /url[\(\u207D\u208D]+/g,
CSS_UNQUOTED_URL = /['\(\)]/g;
var URL_IPV6 = /\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/;
var URI_BLACKLIST_PROTOCOLS = {'javascript':1, 'data':1, 'vbscript':1, 'mhtml':1, 'x-schema':1},
URI_PROTOCOL_COLON = /(?::|[xX]0*3[aA];?|*58;?|:)/,
URI_PROTOCOL_WHITESPACES = /(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,
URI_PROTOCOL_NAMED_REF_MAP = {Tab: '\t', NewLine: '\n'};
var x,
strReplace = function (s, regexp, callback) {
return s === undefined ? 'undefined'
: s === null ? 'null'
: s.toString().replace(regexp, callback);
},
fromCodePoint = String.fromCodePoint || function(codePoint) {
if (arguments.length === 0) {
return '';
}
if (codePoint <= 0xFFFF) {
return String.fromCharCode(codePoint);
}
codePoint -= 0x10000;
return String.fromCharCode((codePoint >> 10) + 0xD800, (codePoint % 0x400) + 0xDC00);
};
function getProtocol(str) {
var s = str.split(URI_PROTOCOL_COLON, 2);
return (s[0] && (s.length === 2 || str.length !== s[0].length)) ? s[0] : null;
}
function htmlDecode(s, namedRefMap, reNamedRef, skipReplacement) {
namedRefMap = namedRefMap || SENSITIVE_NAMED_REF_MAP;
reNamedRef = reNamedRef || SENSITIVE_HTML_ENTITIES;
function regExpFunction(m, num, named, named1) {
if (num) {
num = Number(num[0] <= '9' ? num : '0' + num);
return skipReplacement ? fromCodePoint(num)
: num === 0x80 ? '\u20AC'
: num === 0x82 ? '\u201A'
: num === 0x83 ? '\u0192'
: num === 0x84 ? '\u201E'
: num === 0x85 ? '\u2026'
: num === 0x86 ? '\u2020'
: num === 0x87 ? '\u2021'
: num === 0x88 ? '\u02C6'
: num === 0x89 ? '\u2030'
: num === 0x8A ? '\u0160'
: num === 0x8B ? '\u2039'
: num === 0x8C ? '\u0152'
: num === 0x8E ? '\u017D'
: num === 0x91 ? '\u2018'
: num === 0x92 ? '\u2019'
: num === 0x93 ? '\u201C'
: num === 0x94 ? '\u201D'
: num === 0x95 ? '\u2022'
: num === 0x96 ? '\u2013'
: num === 0x97 ? '\u2014'
: num === 0x98 ? '\u02DC'
: num === 0x99 ? '\u2122'
: num === 0x9A ? '\u0161'
: num === 0x9B ? '\u203A'
: num === 0x9C ? '\u0153'
: num === 0x9E ? '\u017E'
: num === 0x9F ? '\u0178'
: (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD'
: x.frCoPt(num);
}
return namedRefMap[named || named1] || m;
}
return s === undefined ? 'undefined'
: s === null ? 'null'
: s.toString().replace(NULL, '\uFFFD').replace(reNamedRef, regExpFunction);
}
function cssEncode(chr) {
return '\\' + chr.charCodeAt(0).toString(16).toLowerCase() + ' ';
}
function cssBlacklist(s) {
return s.replace(CSS_BLACKLIST, function(m){ return '-x-' + m; });
}
function cssUrl(s) {
s = x.yufull(htmlDecode(s));
var protocol = getProtocol(s);
return (protocol && URI_BLACKLIST_PROTOCOLS[protocol.toLowerCase()]) ? '##' + s : s;
}
return (x = {
frCoPt: function(num) {
return num === undefined || num === null ? '' :
!isFinite(num = Number(num)) ||
num <= 0 ||
num > 0x10FFFF ||
(num >= 0x01 && num <= 0x08) ||
(num >= 0x0E && num <= 0x1F) ||
(num >= 0x7F && num <= 0x9F) ||
(num >= 0xFDD0 && num <= 0xFDEF) ||
num === 0x0B ||
(num & 0xFFFF) === 0xFFFF ||
(num & 0xFFFF) === 0xFFFE ? '\uFFFD' : fromCodePoint(num);
},
d: htmlDecode,
yup: function(s) {
s = getProtocol(s.replace(NULL, ''));
return s ? htmlDecode(s, URI_PROTOCOL_NAMED_REF_MAP, null, true).replace(URI_PROTOCOL_WHITESPACES, '').toLowerCase() : null;
},
y: function(s) {
return strReplace(s, SPECIAL_HTML_CHARS, function (m) {
return m === '&' ? '&'
: m === '<' ? '<'
: m === '>' ? '>'
: m === '"' ? '"'
: m === "'" ? '''
: /*m === '`'*/ '`'; // in hex: 60
});
},
ya: function(s) {
return strReplace(s, AMP, '&');
},
// FOR DETAILS, refer to inHTMLData()
// Reference: https://html.spec.whatwg.org/multipage/syntax.html#data-state
yd: function (s) {
return strReplace(s, LT, '<');
},
yc: function (s) {
return strReplace(s, SPECIAL_COMMENT_CHARS, function(m){
return m === '\x00' ? '\uFFFD'
: m === '--!' || m === '--' || m === '-' || m === ']' ? m + ' '
:/*
: m === ']>' ? '] >'
: m === '-->' ? '-- >'
: m === '--!>' ? '--! >'
: /-*!?>/.test(m) ? */ m.slice(0, -1) + ' >';
});
},
yavd: function (s) {
return strReplace(s, QUOT, '"');
},
yavs: function (s) {
return strReplace(s, SQUOT, ''');
},
yavu: function (s) {
return strReplace(s, SPECIAL_ATTR_VALUE_UNQUOTED_CHARS, function (m) {
return m === '\t' ? ' ' // in hex: 09
: m === '\n' ? '
' // in hex: 0A
: m === '\x0B' ? '' // in hex: 0B for IE. IE<9 \v equals v, so use \x0B instead
: m === '\f' ? '' // in hex: 0C
: m === '\r' ? '
' // in hex: 0D
: m === ' ' ? ' ' // in hex: 20
: m === '=' ? '=' // in hex: 3D
: m === '<' ? '<'
: m === '>' ? '>'
: m === '"' ? '"'
: m === "'" ? '''
: m === '`' ? '`'
: '\uFFFD';
});
},
yu: encodeURI,
yuc: encodeURIComponent,
yubl: function (s) {
return URI_BLACKLIST_PROTOCOLS[x.yup(s)] ? 'x-' + s : s;
},
yufull: function (s) {
return x.yu(s).replace(URL_IPV6, function(m, p) {
return '//[' + p + ']';
});
},
yublf: function (s) {
return x.yubl(x.yufull(s));
},
yceu: function(s) {
s = htmlDecode(s);
return CSS_VALID_VALUE.test(s) ? s : ";-x:'" + cssBlacklist(s.replace(CSS_SINGLE_QUOTED_CHARS, cssEncode)) + "';-v:";
},
yced: function(s) {
return cssBlacklist(htmlDecode(s).replace(CSS_DOUBLE_QUOTED_CHARS, cssEncode));
},
string2 = \'([^\n\r\f\\']|\\{nl}|\\[^\n\r\f0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*\'
yces: function(s) {
return cssBlacklist(htmlDecode(s).replace(CSS_SINGLE_QUOTED_CHARS, cssEncode));
},
yceuu: function(s) {
return cssUrl(s).replace(CSS_UNQUOTED_URL, function (chr) {
return chr === '\'' ? '\\27 ' :
chr === '(' ? '%28' :
/* chr === ')' ? */ '%29';
});
},
yceud: function(s) {
return cssUrl(s);
},
yceus: function(s) {
return cssUrl(s).replace(SQUOT, '\\27 ');
}
});
};
var privFilters = exports._privFilters = exports._getPrivFilters();
function uriInAttr (s, yav, yu) {
return privFilters.yubl(yav((yu || privFilters.yufull)(s)));
}
exports.inHTMLData = privFilters.yd;
exports.inHTMLComment = privFilters.yc;
exports.inSingleQuotedAttr = privFilters.yavs;
exports.inDoubleQuotedAttr = privFilters.yavd;
exports.inUnQuotedAttr = privFilters.yavu;
exports.uriInSingleQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavs);
};
exports.uriInDoubleQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavd);
};
exports.uriInUnQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavu);
};
exports.uriInHTMLData = privFilters.yufull;
exports.uriInHTMLComment = function (s) {
return privFilters.yc(privFilters.yufull(s));
};
exports.uriPathInSingleQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavs, privFilters.yu);
};
exports.uriPathInDoubleQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavd, privFilters.yu);
};
exports.uriPathInUnQuotedAttr = function (s) {
return uriInAttr(s, privFilters.yavu, privFilters.yu);
};
exports.uriPathInHTMLData = privFilters.yu;
exports.uriPathInHTMLComment = function (s) {
return privFilters.yc(privFilters.yu(s));
};
exports.uriQueryInSingleQuotedAttr = exports.uriPathInSingleQuotedAttr;
exports.uriQueryInDoubleQuotedAttr = exports.uriPathInDoubleQuotedAttr;
exports.uriQueryInUnQuotedAttr = exports.uriPathInUnQuotedAttr;
exports.uriQueryInHTMLData = exports.uriPathInHTMLData;
exports.uriQueryInHTMLComment = exports.uriPathInHTMLComment;
exports.uriComponentInSingleQuotedAttr = function (s) {
return privFilters.yavs(privFilters.yuc(s));
};
exports.uriComponentInDoubleQuotedAttr = function (s) {
return privFilters.yavd(privFilters.yuc(s));
};
exports.uriComponentInUnQuotedAttr = function (s) {
return privFilters.yavu(privFilters.yuc(s));
};
exports.uriComponentInHTMLData = privFilters.yuc;
exports.uriComponentInHTMLComment = function (s) {
return privFilters.yc(privFilters.yuc(s));
};
exports.uriFragmentInSingleQuotedAttr = function (s) {
return privFilters.yubl(privFilters.yavs(privFilters.yuc(s)));
};
exports.uriFragmentInDoubleQuotedAttr = function (s) {
return privFilters.yubl(privFilters.yavd(privFilters.yuc(s)));
};
exports.uriFragmentInUnQuotedAttr = function (s) {
return privFilters.yubl(privFilters.yavu(privFilters.yuc(s)));
};
exports.uriFragmentInHTMLData = exports.uriComponentInHTMLData;
exports.uriFragmentInHTMLComment = exports.uriComponentInHTMLComment;
var utils = {
each: function(stack, handler) {
var len = stack.length;
if (len) {
for(var i = 0; i < len; i++) {
if (handler.call(stack[i], stack[i], i) === false) break;
}
}
else if (typeof len === 'undefined') {
for(var name in stack) {
if (handler.call(stack[name], stack[name], name) === false) break;
}
}
},
str_trim: function(string) {
return string.replace(/^\s+/g, '').replace(/\s+$/g, '');
},
arr_compact: function(array) {
var result = [];
utils.each(array, function(item) {
if (utils.str_trim(item) != '') {
result.push(item);
}
});
return result;
},
isObject: function(obj) {
return obj === Object(obj);
},
extend: function(target, obj) {
utils.each(obj, function(value, key) {
target[key] = value;
});
}
};
module.exports = utils;
var utils = require('./utils');
var REGEXP_TAG_STYLE = /